

<!DOCTYPE html>
<html lang="zh-CN" data-default-color-scheme=auto>



<head>
  <meta charset="UTF-8">
  <link rel="apple-touch-icon" sizes="76x76" href="/blog/img/fluid.png">
  <link rel="icon" href="/blog/images/base.png">
  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=5.0, shrink-to-fit=no">
  <meta http-equiv="x-ua-compatible" content="ie=edge">
  
  <meta name="theme-color" content="#2f4154">
  <meta name="author" content="Airfe">
  <meta name="keywords" content="">
  
    <meta name="description" content="本文介绍了断点续传相关技术。">
<meta property="og:type" content="article">
<meta property="og:title" content="断点续存">
<meta property="og:url" content="https://airfe.gitee.io/blog/2024/03/21/%E6%96%AD%E7%82%B9%E7%BB%AD%E5%AD%98/index.html">
<meta property="og:site_name" content="Airfe的博客">
<meta property="og:description" content="本文介绍了断点续传相关技术。">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://markdown-1307246189.cos.ap-chongqing.myqcloud.com/pageImage/%E6%96%AD%E7%82%B9%E7%BB%AD%E4%BC%A0.jpg">
<meta property="article:published_time" content="2024-03-21T00:00:00.000Z">
<meta property="article:modified_time" content="2024-04-13T03:10:11.899Z">
<meta property="article:author" content="Airfe">
<meta property="article:tag" content="分片">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:image" content="https://markdown-1307246189.cos.ap-chongqing.myqcloud.com/pageImage/%E6%96%AD%E7%82%B9%E7%BB%AD%E4%BC%A0.jpg">
  
  
  
    <meta name="referrer" content="no-referrer" />
  
  <title>断点续存 - Airfe的博客</title>

  <link  rel="stylesheet" href="https://lib.baomitu.com/twitter-bootstrap/4.6.1/css/bootstrap.min.css" />



  <link  rel="stylesheet" href="https://lib.baomitu.com/github-markdown-css/4.0.0/github-markdown.min.css" />

  <link  rel="stylesheet" href="https://lib.baomitu.com/hint.css/2.7.0/hint.min.css" />

  <link  rel="stylesheet" href="https://lib.baomitu.com/fancybox/3.5.7/jquery.fancybox.min.css" />



<!-- 主题依赖的图标库，不要自行修改 -->
<!-- Do not modify the link that theme dependent icons -->

<link rel="stylesheet" href="//at.alicdn.com/t/font_1749284_hj8rtnfg7um.css">



<link rel="stylesheet" href="//at.alicdn.com/t/font_1736178_lbnruvf0jn.css">


<link  rel="stylesheet" href="/blog/css/main.css" />


  <link id="highlight-css" rel="stylesheet" href="/blog/css/highlight.css" />
  
    <link id="highlight-css-dark" rel="stylesheet" href="/blog/css/highlight-dark.css" />
  




  <script id="fluid-configs">
    var Fluid = window.Fluid || {};
    Fluid.ctx = Object.assign({}, Fluid.ctx)
    var CONFIG = {"hostname":"airfe.gitee.io","root":"/blog/","version":"1.9.4","typing":{"enable":true,"typeSpeed":70,"cursorChar":"_","loop":false,"scope":[]},"anchorjs":{"enable":true,"element":"h1,h2,h3,h4,h5,h6","placement":"left","visible":"hover","icon":""},"progressbar":{"enable":true,"height_px":3,"color":"#29d","options":{"showSpinner":false,"trickleSpeed":100}},"code_language":{"enable":true,"default":"TEXT"},"copy_btn":true,"image_caption":{"enable":true},"image_zoom":{"enable":true,"img_url_replace":["",""]},"toc":{"enable":true,"placement":"right","headingSelector":"h1,h2,h3,h4,h5,h6","collapseDepth":0},"lazyload":{"enable":true,"loading_img":"/img/loading.gif","onlypost":false,"offset_factor":2},"web_analytics":{"enable":true,"follow_dnt":true,"baidu":"699a5d71ac7179b23874a59b0666a6f6","google":null,"gtag":null,"tencent":{"sid":null,"cid":null},"woyaola":null,"cnzz":null,"leancloud":{"app_id":"RW68dMkEpeIOJJiBr1lPkhOS-gzGzoHsz","app_key":"P5fzMTGSJIoTaGvmgzsUHeNZ","server_url":"https://rw68dmke.lc-cn-n1-shared.com","path":"window.location.pathname","ignore_local":false}},"search_path":"/blog/local-search.xml"};

    if (CONFIG.web_analytics.follow_dnt) {
      var dntVal = navigator.doNotTrack || window.doNotTrack || navigator.msDoNotTrack;
      Fluid.ctx.dnt = dntVal && (dntVal.startsWith('1') || dntVal.startsWith('yes') || dntVal.startsWith('on'));
    }
  </script>
  <script  src="/blog/js/utils.js" ></script>
  <script  src="/blog/js/color-schema.js" ></script>
  

  
    <!-- Baidu Analytics -->
    <script async>
      if (!Fluid.ctx.dnt) {
        var _hmt = _hmt || [];
        (function() {
          var hm = document.createElement("script");
          hm.src = "https://hm.baidu.com/hm.js?699a5d71ac7179b23874a59b0666a6f6";
          var s = document.getElementsByTagName("script")[0];
          s.parentNode.insertBefore(hm, s);
        })();
      }
    </script>
  

  

  

  

  

  

  
    
  



  
<meta name="generator" content="Hexo 6.3.0"></head>


<body>
  

  <header>
    

<div class="header-inner" style="height: 70vh;">
  <nav id="navbar" class="navbar fixed-top  navbar-expand-lg navbar-dark scrolling-navbar">
  <div class="container">
    <a class="navbar-brand" href="/blog/">
      <strong>Airfe</strong>
    </a>

    <button id="navbar-toggler-btn" class="navbar-toggler" type="button" data-toggle="collapse"
            data-target="#navbarSupportedContent"
            aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
      <div class="animated-icon"><span></span><span></span><span></span></div>
    </button>

    <!-- Collapsible content -->
    <div class="collapse navbar-collapse" id="navbarSupportedContent">
      <ul class="navbar-nav ml-auto text-center">
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/blog/">
                <i class="iconfont icon-home-fill"></i>
                <span>首页</span>
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/blog/archives/">
                <i class="iconfont icon-archive-fill"></i>
                <span>归档</span>
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/blog/categories/">
                <i class="iconfont icon-category-fill"></i>
                <span>分类</span>
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/blog/tags/">
                <i class="iconfont icon-tags-fill"></i>
                <span>标签</span>
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/blog/about/">
                <i class="iconfont icon-user-fill"></i>
                <span>关于</span>
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/blog/links/">
                <i class="iconfont icon-link-fill"></i>
                <span>友链</span>
              </a>
            </li>
          
        
        
          <li class="nav-item" id="search-btn">
            <a class="nav-link" target="_self" href="javascript:;" data-toggle="modal" data-target="#modalSearch" aria-label="Search">
              <i class="iconfont icon-search"></i>
            </a>
          </li>
          
        
        
          <li class="nav-item" id="color-toggle-btn">
            <a class="nav-link" target="_self" href="javascript:;" aria-label="Color Toggle">
              <i class="iconfont icon-dark" id="color-toggle-icon"></i>
            </a>
          </li>
        
      </ul>
    </div>
  </div>
</nav>

  

<div id="banner" class="banner" parallax=true
     style="background: url('/blog/images/bg.jpg') no-repeat center center; background-size: cover;">
  <div class="full-bg-img">
    <div class="mask flex-center" style="background-color: rgba(0, 0, 0, 0.3)">
      <div class="banner-text text-center fade-in-up">
        <div class="h2">
          
            <span id="subtitle" data-typed-text="断点续存"></span>
          
        </div>

        
          
  <div class="mt-3">
    
    
      <span class="post-meta">
        <i class="iconfont icon-date-fill" aria-hidden="true"></i>
        <time datetime="2024-03-21 08:00" pubdate>
          2024年03月21日
        </time>
      </span>
    
  </div>

  <div class="mt-1">
    
      <span class="post-meta mr-2">
        <i class="iconfont icon-chart"></i>
        
          19k 字
        
      </span>
    

    
      <span class="post-meta mr-2">
        <i class="iconfont icon-clock-fill"></i>
        
        
        
          157 分钟
        
      </span>
    

    
    
  </div>


        
      </div>

      
    </div>
  </div>
</div>

</div>

  </header>

  <main>
    
      

<div class="container-fluid nopadding-x">
  <div class="row nomargin-x">
    <div class="side-col d-none d-lg-block col-lg-2">
      

    </div>

    <div class="col-lg-8 nopadding-x-md">
      <div class="container nopadding-x-md" id="board-ctn">
        <div id="board">
          <article class="post-content mx-auto">
            <!-- SEO header -->
            <h1 style="display: none">断点续存</h1>
            
            
              <div class="markdown-body">
                
                <h1 id="断点续存"><a href="#断点续存" class="headerlink" title="断点续存"></a>断点续存</h1><p>原理：允许在上传中断后继续上传。根本上还是通过<strong>文件分片</strong>上传实现的，<strong>记录分片的上传情况</strong>和<strong>整体的上传进度</strong>，从而实现可以恢复之前进度的功能。</p>
<p>可以解决</p>
<ul>
<li>1G的文件按照正常的20M的带宽（上行20M已经属于很快的带宽），我们可能需要在页面停留大约9分钟（大概时间，甚至更久）。正常用户都无法忍受9分钟什么都不做，等着文件上传</li>
<li>由于文件过大，上传时间过长，中途断网或者浏览器崩溃，都会导致上传中断。可能就差几M就成功的文件，导致下次又要继续从头开始上传</li>
<li>同一个文件多次上传，浪费服务器资源</li>
</ul>
<h1 id="基于element-ui-自定义封装大文件上传组件"><a href="#基于element-ui-自定义封装大文件上传组件" class="headerlink" title="基于element-ui 自定义封装大文件上传组件"></a>基于element-ui 自定义封装大文件上传组件</h1><h2 id="前端代码"><a href="#前端代码" class="headerlink" title="前端代码"></a>前端代码</h2><ul>
<li>获取文件，调校验文件状态的接口，询问后端这个文件是否已上传，如果上传过的话后端会直接返回访问url，速度很快（秒传）；</li>
<li>如果上传过一部分分片，就根据返回已上传的分片信息，只选择哪些还没上传过的分片上传。</li>
<li>如果从来没有上传过，就上传所有的分片</li>
</ul>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><code class="hljs vue">&lt;div class=&quot;big-file-box&quot;&gt;<br> &lt;div  @click=&quot;handleClick&quot;&gt;<br>     &lt;slot&gt;&lt;/slot&gt;<br>     &lt;input class=&quot;el-upload__input&quot; type=&quot;file&quot; ref=&quot;input&quot; name=&quot;请上传文件&quot; @change=&#x27;handleChange&#x27; :multiple=&#x27;multiple&#x27; :accept=&#x27;accept&#x27;&gt;&lt;/input&gt; <br> &lt;/div&gt;<br> &lt;slot name=&quot;tip&quot;&gt;&lt;/slot&gt;<br> &lt;div class=&quot;file-box&quot;&gt;<br>     &lt;transition-group tag=&quot;ul&quot;&gt;<br>         &lt;li v-for=&quot;item in uploadFiles&quot;<br>             :key=&quot;item.uid&quot;<br>             tabindex=&quot;0&quot;<br>             :class=&quot;&#123;&#x27;file-li&#x27;:true&#125;&quot;<br>             @mouseover=&quot;handleMouseover(item.uid)&quot;<br>             @mouseleave=&quot;handleMouseleave(item.uid)&quot;<br>         &gt;<br>             &lt;i class=&quot;el-icon-document&quot;&gt;&lt;/i&gt;<br>             &lt;span class=&quot;file-name&quot; @click=&quot;handleClickFile(item)&quot;&gt;&#123;&#123;item.name || item.url&#125;&#125;&lt;/span&gt;<br>             &lt;i v-if=&quot;item.status === &#x27;success&#x27;&quot; :class=&quot;item.uid === listChecked ? &#x27;el-icon-close deleteColor&#x27;: &#x27;el-icon-circle-check passColor&#x27;&quot; @click=&quot;hanldeRemoveFile(item)&quot;&gt;&lt;/i&gt;<br>             &lt;el-progress<br>                 v-if=&quot;item.status === &#x27;uploading&#x27;&quot;<br>                 type=&quot;line&quot;<br>                 :stroke-width=&quot;2&quot;<br>                 :percentage=&quot;Number(item.percentage.toFixed(1))&quot;&gt;<br>             &lt;/el-progress&gt;<br>         &lt;/li&gt;<br>     &lt;/transition-group&gt;<br>     &lt;/div&gt;<br> &lt;/div&gt;<br></code></pre></td></tr></table></figure>

<h3 id="第一步：选取文件"><a href="#第一步：选取文件" class="headerlink" title="第一步：选取文件"></a>第一步：选取文件</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">// 重置上一次的文件，接着主动触发input 的click事件</span><br><span class="hljs-title function_">handleClick</span>(<span class="hljs-params"></span>) &#123;<br>    <span class="hljs-variable language_">this</span>.<span class="hljs-property">$refs</span>.<span class="hljs-property">input</span>.<span class="hljs-property">value</span> = <span class="hljs-literal">null</span>;<br>    <span class="hljs-variable language_">this</span>.<span class="hljs-property">$refs</span>.<span class="hljs-property">input</span>.<span class="hljs-title function_">click</span>();<br>&#125;<br></code></pre></td></tr></table></figure>

<h3 id="第二步：判断文件规范性"><a href="#第二步：判断文件规范性" class="headerlink" title="第二步：判断文件规范性"></a>第二步：判断文件规范性</h3><ul>
<li><p>触发input的change事件，开始判断是否已选取文件，接着判断文件个数，如果超出限制，会直接终止当前逻辑并将文件，以及文件列表抛给父组件的onExceed 函数，父组件自行给出提示；</p>
</li>
<li><p>如果未超过限制，继续执行上传逻辑执行 upload 方法, upload 方法会调用beforeUpload 方法是否符合文件类型，如果返回ture, <strong>继续执行，开始读取大文件的md5</strong></p>
</li>
</ul>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">async</span> <span class="hljs-title function_">handleChange</span>(<span class="hljs-params">ev</span>)&#123;<br>    <span class="hljs-keyword">const</span> files = ev.<span class="hljs-property">target</span>.<span class="hljs-property">files</span>;<br>    <span class="hljs-keyword">if</span> (!files) <span class="hljs-keyword">return</span>;<br>    <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">uploadExceedFiles</span>(files);<br>&#125;,<br><br><span class="hljs-title function_">uploadExceedFiles</span>(<span class="hljs-params">files</span>) &#123;<br>    <span class="hljs-keyword">if</span> (<span class="hljs-variable language_">this</span>.<span class="hljs-property">limit</span> &amp;&amp; <span class="hljs-variable language_">this</span>.<span class="hljs-property">fileList</span>.<span class="hljs-property">length</span> + files.<span class="hljs-property">length</span> &gt; <span class="hljs-variable language_">this</span>.<span class="hljs-property">limit</span>) &#123;<br>        <span class="hljs-comment">//大于限制数量，父组件处理自己的逻辑</span><br>        <span class="hljs-variable language_">this</span>.<span class="hljs-property">onExceed</span> &amp;&amp; <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">onExceed</span>(files, <span class="hljs-variable language_">this</span>.<span class="hljs-property">fileList</span>);<br>        <span class="hljs-keyword">return</span>;<br>    &#125;<br>    <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">upload</span>(files)<br>&#125;,<br><br><span class="hljs-keyword">async</span> <span class="hljs-title function_">upload</span>(<span class="hljs-params">files</span>)&#123;<br>    <span class="hljs-keyword">if</span> (!<span class="hljs-variable language_">this</span>.<span class="hljs-property">beforeUpload</span>) &#123;<br>        <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">readFile</span>(files[<span class="hljs-number">0</span>]);<br>    &#125;<br>    <span class="hljs-keyword">const</span> before = <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">beforeUpload</span>(files[<span class="hljs-number">0</span>]);<br>    <span class="hljs-keyword">if</span>(before) &#123;<br>        <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">readFile</span>(files[<span class="hljs-number">0</span>])<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<h3 id="第三步：文件切片上传"><a href="#第三步：文件切片上传" class="headerlink" title="第三步：文件切片上传"></a>第三步：文件切片上传</h3><p>首先将文件开始切片,放入切片list中，接着开始读取文件，这里可以自行在父组件中调用 onReadingFile 方法设置loading状态，提升用户体验度。 接着会直接调用服务单接口，检查是否已经上传过，并将已上传的分片序号写入到一个isUploadChuncks list中，然后循环上传未上片段，这里会执行 onStart 方法，给每个文件一个初始对象，设置文件的初始状态，以及文件内容，插入到已上传的文件列表 uploadFiles 中，为后根据文件状态展示进度条，以及上传失败时删除对应文件列表做准备</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">async</span> <span class="hljs-title function_">readFile</span>(<span class="hljs-params">files</span>) &#123;<br>    <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">sliceFile</span>(files);<br>    <span class="hljs-comment">//注意这里，开始读取文件，会回调父组件的onreadingFile,告诉组件开始读取，此时父组件开始设置读取的loading 状态，读取完成之后再次调用会返回end表示读取结束，此时将loading状态改为false</span><br>    <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">onReadingFile</span>(<span class="hljs-string">&#x27;start&#x27;</span>);<br>    <span class="hljs-keyword">const</span> data = <span class="hljs-keyword">await</span> <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">getFileMD5</span>(files);<br>    <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">onReadingFile</span>(<span class="hljs-string">&#x27;end&#x27;</span>);<br>    <span class="hljs-comment">//判断是否上传重复文件</span><br>    <span class="hljs-keyword">const</span> hasSameFile = <span class="hljs-variable language_">this</span>.<span class="hljs-property">uploadFiles</span>.<span class="hljs-title function_">findIndex</span>(<span class="hljs-function"><span class="hljs-params">item</span>=&gt;</span> item.<span class="hljs-property">hash</span> ===data);<br>    <span class="hljs-keyword">if</span>(hasSameFile === -<span class="hljs-number">1</span>) &#123;<br>        <span class="hljs-variable language_">this</span>.<span class="hljs-property">fileSparkMD5</span> = &#123;<span class="hljs-attr">md5Value</span>:data,<span class="hljs-attr">fileKey</span>:files.<span class="hljs-property">name</span>&#125;;<br>        <span class="hljs-keyword">const</span> hasChuncks = <span class="hljs-keyword">await</span> <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">checkFile</span>(data,files.<span class="hljs-property">name</span>); <span class="hljs-comment">//是否上传过</span><br>        <span class="hljs-keyword">let</span> isSuccess = <span class="hljs-literal">true</span>; <span class="hljs-comment">//同步上传成功标记</span><br>        <span class="hljs-comment">//断点续传</span><br>        <span class="hljs-keyword">if</span>(hasChuncks) &#123;<br>            <span class="hljs-keyword">const</span> hasEmptyChunk = <span class="hljs-variable language_">this</span>.<span class="hljs-property">isUploadChuncks</span>.<span class="hljs-title function_">findIndex</span>(<span class="hljs-function"><span class="hljs-params">item</span> =&gt;</span> item === <span class="hljs-number">0</span>);<br>            <span class="hljs-comment">//上传过,并且已经完整上传，直接提示上传成功（秒传）</span><br>            <span class="hljs-keyword">if</span>(hasEmptyChunk === -<span class="hljs-number">1</span>) &#123;<br>                <span class="hljs-keyword">let</span> file = &#123;<br>                    <span class="hljs-attr">status</span>: <span class="hljs-string">&#x27;success&#x27;</span>,<br>                    <span class="hljs-attr">percentage</span>: <span class="hljs-number">100</span>,<br>                    <span class="hljs-attr">uid</span>: <span class="hljs-title class_">Date</span>.<span class="hljs-title function_">now</span>() + <span class="hljs-variable language_">this</span>.<span class="hljs-property">tempIndex</span>++,<br>                    <span class="hljs-attr">hash</span>:data,<br>                    <span class="hljs-attr">name</span>:<span class="hljs-string">&#x27;&#x27;</span>,<br>                    <span class="hljs-attr">url</span>:<span class="hljs-string">&#x27;&#x27;</span><br>                &#125;;<br>                <span class="hljs-variable language_">this</span>.<span class="hljs-property">uploadFiles</span>.<span class="hljs-title function_">push</span>(file);<br>                <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">onSuccess</span>(file);<br>                <span class="hljs-keyword">return</span>;<br>            &#125;  <span class="hljs-keyword">else</span> &#123;<br>                <span class="hljs-comment">//处理续传逻辑，上传检测之后未上传的分片</span><br>                <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">onStart</span>(files,data);<br>                <span class="hljs-keyword">const</span> emptyLength = <span class="hljs-variable language_">this</span>.<span class="hljs-property">isUploadChuncks</span>.<span class="hljs-title function_">filter</span>(<span class="hljs-function"><span class="hljs-params">item</span> =&gt;</span> item === <span class="hljs-number">0</span>);<br>                <span class="hljs-keyword">for</span>(<span class="hljs-keyword">let</span> k = <span class="hljs-number">0</span>; k &lt; <span class="hljs-variable language_">this</span>.<span class="hljs-property">isUploadChuncks</span>.<span class="hljs-property">length</span>; k++) &#123;<br>                    <span class="hljs-keyword">if</span>(<span class="hljs-variable language_">this</span>.<span class="hljs-property">isUploadChuncks</span>[k] !== <span class="hljs-number">1</span>) &#123;<br>                        <span class="hljs-keyword">let</span> formData = <span class="hljs-keyword">new</span> <span class="hljs-title class_">FormData</span>();<br>                        formData.<span class="hljs-title function_">append</span>(<span class="hljs-string">&#x27;totalNumber&#x27;</span>,<span class="hljs-variable language_">this</span>.<span class="hljs-property">fileChuncks</span>.<span class="hljs-property">length</span>);<br>                        formData.<span class="hljs-title function_">append</span>(<span class="hljs-string">&quot;chunkSize&quot;</span>,<span class="hljs-variable language_">this</span>.<span class="hljs-property">chunckSize</span>);<br>                        formData.<span class="hljs-title function_">append</span>(<span class="hljs-string">&quot;partNumber&quot;</span>,k);<br>                        formData.<span class="hljs-title function_">append</span>(<span class="hljs-string">&#x27;uuid&#x27;</span>,<span class="hljs-variable language_">this</span>.<span class="hljs-property">fileSparkMD5</span>.<span class="hljs-property">md5Value</span>);<br>                        formData.<span class="hljs-title function_">append</span>(<span class="hljs-string">&#x27;name&#x27;</span>,<span class="hljs-variable language_">this</span>.<span class="hljs-property">fileSparkMD5</span>.<span class="hljs-property">fileKey</span>);<br>                        formData.<span class="hljs-title function_">append</span>(<span class="hljs-string">&#x27;file&#x27;</span>,<span class="hljs-keyword">new</span> <span class="hljs-title class_">File</span>([<span class="hljs-variable language_">this</span>.<span class="hljs-property">fileChuncks</span>[k].<span class="hljs-property">fileChuncks</span>],<span class="hljs-variable language_">this</span>.<span class="hljs-property">fileSparkMD5</span>.<span class="hljs-property">fileKey</span>))<br>                        <span class="hljs-comment">//如果并发请求，走这里</span><br>                        <span class="hljs-keyword">if</span>(<span class="hljs-variable language_">this</span>.<span class="hljs-property">concurrentUpload</span>) &#123;<br>                            <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">post</span>(formData,k,emptyLength.<span class="hljs-property">length</span>,data); <br>                        &#125;<span class="hljs-keyword">else</span> &#123;<br>                            isSuccess = <span class="hljs-keyword">await</span> <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">post</span>(formData,k,emptyLength.<span class="hljs-property">length</span>,data);<span class="hljs-comment">//这注意分片总数，因为进度条是根据分片个数来算的，所以分母应该是未上传的分片总数</span><br>                            <span class="hljs-keyword">if</span>(!isSuccess) &#123;<br>                                <span class="hljs-keyword">break</span>;<br>                            &#125;<br>                        &#125;<br>                    &#125;<br>                &#125;<br>                <span class="hljs-comment">//兼容并发与同步请求操作，受服务器带宽影响，做并发与同步请求处理</span><br>                <span class="hljs-keyword">if</span>(<span class="hljs-variable language_">this</span>.<span class="hljs-property">concurrentUpload</span>) &#123;<br>                    <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">uploadSuccess</span>();<br>                &#125;<span class="hljs-keyword">else</span> &#123;<br>                    <span class="hljs-keyword">if</span>(isSuccess) &#123;<br>                        <span class="hljs-comment">//执行玩循环，如果isSuccess还是true,说明所有分片已上传，可执行合并文件接口</span><br>                        <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">mergeFile</span>(<span class="hljs-variable language_">this</span>.<span class="hljs-property">fileSparkMD5</span>,<span class="hljs-variable language_">this</span>.<span class="hljs-property">fileChuncks</span>.<span class="hljs-property">length</span>);<br>                    &#125;<span class="hljs-keyword">else</span> &#123;<br>                        <span class="hljs-keyword">const</span> index = <span class="hljs-variable language_">this</span>.<span class="hljs-property">uploadFiles</span>.<span class="hljs-title function_">findIndex</span>(<span class="hljs-function"><span class="hljs-params">item</span> =&gt;</span> item.<span class="hljs-property">hash</span> === <span class="hljs-variable language_">this</span>.<span class="hljs-property">fileSparkMD5</span>.<span class="hljs-property">md5Value</span>);<br>                        <span class="hljs-variable language_">this</span>.$set(<span class="hljs-variable language_">this</span>.<span class="hljs-property">uploadFiles</span>,index,&#123;...<span class="hljs-variable language_">this</span>.<span class="hljs-property">uploadFiles</span>[index],...&#123;<span class="hljs-attr">status</span>: <span class="hljs-string">&#x27;error&#x27;</span>&#125;&#125;); <span class="hljs-comment">//后续拓展继续上传时可用</span><br>                        <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">hanldeRemoveFile</span>(<span class="hljs-variable language_">this</span>.<span class="hljs-property">uploadFiles</span>[index]);<br>                        <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">onError</span>(<span class="hljs-variable language_">this</span>.<span class="hljs-property">uploadFiles</span>[index]);<br>                    &#125;<br>                &#125;<br>            &#125;<br>        &#125;<span class="hljs-keyword">else</span> &#123;<br>            <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">onStart</span>(files,data);<br>            <span class="hljs-comment">// this.sliceFile(files);</span><br>            <span class="hljs-comment">//同步上传</span><br>            <span class="hljs-keyword">for</span>(<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; <span class="hljs-variable language_">this</span>.<span class="hljs-property">fileChuncks</span>.<span class="hljs-property">length</span>; i++) &#123;<br>                <span class="hljs-keyword">let</span> formData = <span class="hljs-keyword">new</span> <span class="hljs-title class_">FormData</span>();<br>                formData.<span class="hljs-title function_">append</span>(<span class="hljs-string">&#x27;totalNumber&#x27;</span>,<span class="hljs-variable language_">this</span>.<span class="hljs-property">fileChuncks</span>.<span class="hljs-property">length</span>);<br>                formData.<span class="hljs-title function_">append</span>(<span class="hljs-string">&quot;chunkSize&quot;</span>,<span class="hljs-variable language_">this</span>.<span class="hljs-property">chunckSize</span>);<br>                formData.<span class="hljs-title function_">append</span>(<span class="hljs-string">&quot;partNumber&quot;</span>,i);<br>                formData.<span class="hljs-title function_">append</span>(<span class="hljs-string">&#x27;uuid&#x27;</span>,<span class="hljs-variable language_">this</span>.<span class="hljs-property">fileSparkMD5</span>.<span class="hljs-property">md5Value</span>);<br>                formData.<span class="hljs-title function_">append</span>(<span class="hljs-string">&#x27;name&#x27;</span>,<span class="hljs-variable language_">this</span>.<span class="hljs-property">fileSparkMD5</span>.<span class="hljs-property">fileKey</span>);<br>                formData.<span class="hljs-title function_">append</span>(<span class="hljs-string">&#x27;file&#x27;</span>,<span class="hljs-keyword">new</span> <span class="hljs-title class_">File</span>([<span class="hljs-variable language_">this</span>.<span class="hljs-property">fileChuncks</span>[i].<span class="hljs-property">fileChuncks</span>],<span class="hljs-variable language_">this</span>.<span class="hljs-property">fileSparkMD5</span>.<span class="hljs-property">fileKey</span>));<br>                <span class="hljs-keyword">if</span>(<span class="hljs-variable language_">this</span>.<span class="hljs-property">concurrentUpload</span>) &#123;<br>                    <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">post</span>(formData,k,emptyLength.<span class="hljs-property">length</span>,data); <br>                &#125;<span class="hljs-keyword">else</span> &#123;<br>                    isSuccess = <span class="hljs-keyword">await</span> <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">post</span>(formData,i,<span class="hljs-variable language_">this</span>.<span class="hljs-property">fileChuncks</span>.<span class="hljs-property">length</span>,data);<span class="hljs-comment">//这注意分片总数，因为进度条是根据分片个数来算的，所以分母应该是未上传的分片总数</span><br>                    <span class="hljs-keyword">if</span>(!isSuccess) &#123;<br>                        <span class="hljs-keyword">break</span>;<br>                    &#125;<br>                &#125;<br>            &#125;<br>            <span class="hljs-comment">//兼容并发与同步请求操作，受服务器带宽影响，做并发与同步请求处理</span><br>            <span class="hljs-keyword">if</span>(<span class="hljs-variable language_">this</span>.<span class="hljs-property">concurrentUpload</span>) &#123;<br>                <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">uploadSuccess</span>();<br>            &#125;<span class="hljs-keyword">else</span> &#123;<br>                <span class="hljs-comment">//循环所有的片段后，isSuccess依然为ture</span><br>                <span class="hljs-keyword">if</span>(isSuccess) &#123;<br>                    <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">mergeFile</span>(<span class="hljs-variable language_">this</span>.<span class="hljs-property">fileSparkMD5</span>,<span class="hljs-variable language_">this</span>.<span class="hljs-property">fileChuncks</span>.<span class="hljs-property">length</span>);<br>                &#125;<span class="hljs-keyword">else</span> &#123;<br>                    <span class="hljs-keyword">const</span> index = <span class="hljs-variable language_">this</span>.<span class="hljs-property">uploadFiles</span>.<span class="hljs-title function_">findIndex</span>(<span class="hljs-function"><span class="hljs-params">item</span> =&gt;</span> item.<span class="hljs-property">hash</span> === <span class="hljs-variable language_">this</span>.<span class="hljs-property">fileSparkMD5</span>.<span class="hljs-property">md5Value</span>);<br>                    <span class="hljs-variable language_">this</span>.$set(<span class="hljs-variable language_">this</span>.<span class="hljs-property">uploadFiles</span>,index,&#123;...<span class="hljs-variable language_">this</span>.<span class="hljs-property">uploadFiles</span>[index],...&#123;<span class="hljs-attr">status</span>: <span class="hljs-string">&#x27;error&#x27;</span>&#125;&#125;); <span class="hljs-comment">//后续拓展继续上传时可用</span><br>                    <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">hanldeRemoveFile</span>(<span class="hljs-variable language_">this</span>.<span class="hljs-property">uploadFiles</span>[index]);<br>                    <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">onError</span>(<span class="hljs-variable language_">this</span>.<span class="hljs-property">uploadFiles</span>[index]);<br>                &#125;<br>            &#125;<br>        &#125;<br>    &#125;<span class="hljs-keyword">else</span> &#123;<br>        <span class="hljs-variable language_">this</span>.<span class="hljs-property">$message</span>.<span class="hljs-title function_">error</span>(<span class="hljs-string">&#x27;Please do not upload the same file repeatedly&#x27;</span>);<br>    &#125;<br>&#125;,<br><br><span class="hljs-title function_">onStart</span>(<span class="hljs-params">rawFile,hash</span>) &#123;<br>    rawFile.<span class="hljs-property">uid</span> = <span class="hljs-title class_">Date</span>.<span class="hljs-title function_">now</span>() + <span class="hljs-variable language_">this</span>.<span class="hljs-property">tempIndex</span>++;<br>    <span class="hljs-keyword">let</span> file = &#123;<br>        <span class="hljs-attr">status</span>: <span class="hljs-string">&#x27;ready&#x27;</span>,<br>        <span class="hljs-attr">name</span>: rawFile.<span class="hljs-property">name</span>,<br>        <span class="hljs-attr">size</span>: rawFile.<span class="hljs-property">size</span>,<br>        <span class="hljs-attr">percentage</span>: <span class="hljs-number">0</span>,<br>        <span class="hljs-attr">uid</span>: rawFile.<span class="hljs-property">uid</span>,<br>        <span class="hljs-attr">raw</span>: rawFile,<br>        hash<br>    &#125;;<br>    <span class="hljs-variable language_">this</span>.<span class="hljs-property">uploadFiles</span>.<span class="hljs-title function_">push</span>(file);<br>    <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">onChange</span>(file, <span class="hljs-variable language_">this</span>.<span class="hljs-property">uploadFiles</span>);<br>&#125;,<br><br>sliceFile (file) &#123;<br>    <span class="hljs-comment">//文件分片之后的集合</span><br>    <span class="hljs-keyword">const</span> chuncks = [];<br>    <span class="hljs-keyword">let</span> start = <span class="hljs-number">0</span> ;<br>    <span class="hljs-keyword">let</span> end;<br>    <span class="hljs-keyword">while</span>(start &lt; file.<span class="hljs-property">size</span>) &#123;<br>        end = <span class="hljs-title class_">Math</span>.<span class="hljs-title function_">min</span>(start + <span class="hljs-variable language_">this</span>.<span class="hljs-property">chunckSize</span>,file.<span class="hljs-property">size</span>);<br>        chuncks.<span class="hljs-title function_">push</span>(&#123;<span class="hljs-attr">fileChuncks</span>:file.<span class="hljs-title function_">slice</span>(start,end),<span class="hljs-attr">fileName</span>:file.<span class="hljs-property">name</span>&#125;); <br>        start = end;<br>    &#125;<br>    <span class="hljs-variable language_">this</span>.<span class="hljs-property">fileChuncks</span> = [...chuncks];<br>&#125;,<br><br> getFileMD5 (file)&#123;<br>    <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">Promise</span>(<span class="hljs-function">(<span class="hljs-params">resolve, reject</span>) =&gt;</span> &#123;<br>        <span class="hljs-keyword">const</span> fileReader = <span class="hljs-keyword">new</span> <span class="hljs-title class_">FileReader</span>();<br>        fileReader.<span class="hljs-property">onload</span> = <span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span>&#123;<br>            <span class="hljs-keyword">const</span> fileMd5 = <span class="hljs-variable language_">this</span>.<span class="hljs-property">SparkMD5</span>.<span class="hljs-property">ArrayBuffer</span>.<span class="hljs-title function_">hash</span>(e.<span class="hljs-property">target</span>.<span class="hljs-property">result</span>);<br>            <span class="hljs-title function_">resolve</span>(fileMd5)<br>        &#125;<br>        fileReader.<span class="hljs-property">onerror</span> = <span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span>&#123;<br>            <span class="hljs-title function_">reject</span>(<span class="hljs-string">&#x27;file read failure&#x27;</span>,e)<br>            <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">onError</span>(file,<span class="hljs-string">&#x27;file read failure&#x27;</span>)<br>        &#125;<br>        fileReader.<span class="hljs-title function_">readAsArrayBuffer</span>(file);<br>    &#125;)<br>&#125;,<br><br><span class="hljs-keyword">async</span> <span class="hljs-title function_">checkFile</span>(<span class="hljs-params">md5Hash,fileName</span>) &#123;<br>    <span class="hljs-keyword">const</span> &#123;code,data&#125; = <span class="hljs-keyword">await</span> <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">request</span>(&#123;<span class="hljs-attr">url</span>:<span class="hljs-string">`<span class="hljs-subst">$&#123;<span class="hljs-variable language_">this</span>.checkApi&#125;</span>?uuid=<span class="hljs-subst">$&#123;md5Hash&#125;</span>&amp;fileName=<span class="hljs-subst">$&#123;fileName&#125;</span>`</span>, <span class="hljs-attr">method</span>: <span class="hljs-string">&#x27;get&#x27;</span>&#125;);<br>    <span class="hljs-keyword">if</span>(code === <span class="hljs-number">200</span>) &#123;<br>        <span class="hljs-keyword">if</span>(data.<span class="hljs-property">length</span>) &#123;<br>            <span class="hljs-keyword">const</span> newArr = <span class="hljs-keyword">new</span> <span class="hljs-title class_">Array</span>(<span class="hljs-title class_">Number</span>(<span class="hljs-variable language_">this</span>.<span class="hljs-property">fileChuncks</span>.<span class="hljs-property">length</span>)).<span class="hljs-title function_">fill</span>(<span class="hljs-number">0</span>); <span class="hljs-comment">// [1,1,0,1,1]</span><br>            <span class="hljs-keyword">const</span> chunckNumberArr = data.<span class="hljs-title function_">map</span>(<span class="hljs-function"><span class="hljs-params">item</span> =&gt;</span> item);<br>            chunckNumberArr.<span class="hljs-title function_">forEach</span>(<span class="hljs-function">(<span class="hljs-params">item,index</span>) =&gt;</span> &#123;<br>                newArr[item] = <span class="hljs-number">1</span><br>            &#125;);<br>            <span class="hljs-variable language_">this</span>.<span class="hljs-property">isUploadChuncks</span> = [...newArr];<br>            <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;<br><br>        &#125;<span class="hljs-keyword">else</span> &#123;<br>            <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;<br>        &#125;<br>    &#125;<br>&#125;<br><br><span class="hljs-comment">//并发请求，推入promise 数组中，通过allSettled 方法来判断，所有任务是否都为resove状态，如果有是，就进行合并文件</span><br><span class="hljs-title function_">uploadSuccess</span>(<span class="hljs-params"></span>) &#123;<br>    <span class="hljs-title class_">Promise</span>.<span class="hljs-title function_">allSettled</span>(<span class="hljs-variable language_">this</span>.<span class="hljs-property">promiseArr</span>).<span class="hljs-title function_">then</span>(<span class="hljs-function"><span class="hljs-params">result</span>=&gt;</span>&#123;<br>        <span class="hljs-keyword">const</span> hasReject = result.<span class="hljs-title function_">findIndex</span>(<span class="hljs-function"><span class="hljs-params">item</span> =&gt;</span> item.<span class="hljs-property">status</span> === <span class="hljs-string">&#x27;rejected&#x27;</span>);<br>        <span class="hljs-keyword">if</span>(hasReject === -<span class="hljs-number">1</span>) &#123;<br>            <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">mergeFile</span>(<span class="hljs-variable language_">this</span>.<span class="hljs-property">fileSparkMD5</span>,<span class="hljs-variable language_">this</span>.<span class="hljs-property">fileChuncks</span>.<span class="hljs-property">length</span>);<br>        &#125;<span class="hljs-keyword">else</span> &#123;<br>            <span class="hljs-keyword">const</span> index = <span class="hljs-variable language_">this</span>.<span class="hljs-property">uploadFiles</span>.<span class="hljs-title function_">findIndex</span>(<span class="hljs-function"><span class="hljs-params">item</span> =&gt;</span> item.<span class="hljs-property">hash</span> === result[hasReject].<span class="hljs-property">reason</span>);<br>            <span class="hljs-variable language_">this</span>.$set(<span class="hljs-variable language_">this</span>.<span class="hljs-property">uploadFiles</span>,index,&#123;...<span class="hljs-variable language_">this</span>.<span class="hljs-property">uploadFiles</span>[index],...&#123;<span class="hljs-attr">status</span>: <span class="hljs-string">&#x27;error&#x27;</span>&#125;&#125;); <span class="hljs-comment">//后续拓展继续上传时可用</span><br>            <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">hanldeRemoveFile</span>(<span class="hljs-variable language_">this</span>.<span class="hljs-property">uploadFiles</span>[index]);<br>            <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">onError</span>(<span class="hljs-variable language_">this</span>.<span class="hljs-property">uploadFiles</span>[index]);<br>        &#125;<br>    &#125;).<span class="hljs-title function_">catch</span>(<span class="hljs-function"><span class="hljs-params">e</span>=&gt;</span>&#123;<br>        <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">onError</span>(e);<br>    &#125;).<span class="hljs-title function_">finally</span>(<span class="hljs-function"><span class="hljs-params">e</span>=&gt;</span>&#123;<br>        <span class="hljs-variable language_">this</span>.<span class="hljs-property">promiseArr</span> = [];<br>        <span class="hljs-variable language_">this</span>.<span class="hljs-property">uploadQuantity</span>  = <span class="hljs-number">0</span>; <span class="hljs-comment">//重置上传进度</span><br>    &#125;)<br>&#125;,<br><br></code></pre></td></tr></table></figure>

<p>上传逻辑</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">//file：当前文件，nowChunck:当前分片索引，totalChunck:当前需要上传文件分片的总数，hash:文件的唯一hash值</span><br><span class="hljs-keyword">async</span> <span class="hljs-title function_">post</span>(<span class="hljs-params">file,nowChunck,totalChunck,hash</span>) &#123;<br>    <span class="hljs-keyword">let</span> _this = <span class="hljs-variable language_">this</span>;<br>    <span class="hljs-keyword">const</span> index = _this.<span class="hljs-property">uploadFiles</span>.<span class="hljs-title function_">findIndex</span>(<span class="hljs-function"><span class="hljs-params">item</span> =&gt;</span> item.<span class="hljs-property">hash</span> === hash);<br>    _this.$set(_this.<span class="hljs-property">uploadFiles</span>,index,&#123;..._this.<span class="hljs-property">uploadFiles</span>[index],...&#123;<span class="hljs-attr">status</span>: <span class="hljs-string">&#x27;uploading&#x27;</span>&#125;&#125;);<br>    <span class="hljs-keyword">const</span> curPormise = <span class="hljs-keyword">new</span> <span class="hljs-title class_">Promise</span>(<span class="hljs-function">(<span class="hljs-params">resolve,reject</span>)=&gt;</span>&#123;<br>        <span class="hljs-keyword">let</span> xhr = <span class="hljs-keyword">new</span> <span class="hljs-title class_">XMLHttpRequest</span>();<br>        <span class="hljs-comment">// 当上传完成时调用</span><br>        xhr.<span class="hljs-property">onload</span> = <span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) &#123;<br>            <span class="hljs-keyword">if</span> (xhr.<span class="hljs-property">status</span> === <span class="hljs-number">200</span>) &#123;<br>                <span class="hljs-keyword">const</span> index = _this.<span class="hljs-property">uploadFiles</span>.<span class="hljs-title function_">findIndex</span>(<span class="hljs-function"><span class="hljs-params">item</span> =&gt;</span> item.<span class="hljs-property">hash</span> === hash);<br>                <span class="hljs-comment">//大文件上传进度</span><br>                _this.<span class="hljs-property">uploadQuantity</span> ++;<br>                _this.$set(_this.<span class="hljs-property">uploadFiles</span>,index,&#123;..._this.<span class="hljs-property">uploadFiles</span>[index],...&#123;<span class="hljs-attr">status</span>: <span class="hljs-string">&#x27;uploading&#x27;</span>,<span class="hljs-attr">percentage</span>:_this.<span class="hljs-property">uploadQuantity</span> / totalChunck * <span class="hljs-number">100</span>&#125;&#125;);<br>                _this.<span class="hljs-title function_">onProgress</span>(file,_this.<span class="hljs-property">uploadQuantity</span> / totalChunck * <span class="hljs-number">100</span>);<br>                <span class="hljs-title function_">resolve</span>(<span class="hljs-literal">true</span>);<br>            &#125;<span class="hljs-keyword">else</span> &#123;<br>                _this.<span class="hljs-property">errorChuncks</span>.<span class="hljs-title function_">push</span>(&#123;<span class="hljs-attr">file</span>:file,nowChunck,totalChunck,hash&#125;);<br>                <span class="hljs-title function_">reject</span>(<span class="hljs-literal">false</span>);<br>                _this.<span class="hljs-property">uploadQuantity</span> = <span class="hljs-number">0</span>;<br>                <span class="hljs-keyword">const</span> index = _this.<span class="hljs-property">uploadFiles</span>.<span class="hljs-title function_">findIndex</span>(<span class="hljs-function"><span class="hljs-params">item</span> =&gt;</span> item.<span class="hljs-property">hash</span> === hash);<br>                _this.$set(_this.<span class="hljs-property">uploadFiles</span>,index,&#123;..._this.<span class="hljs-property">uploadFiles</span>[index],...&#123;<span class="hljs-attr">status</span>: <span class="hljs-string">&#x27;error&#x27;</span>&#125;&#125;); <span class="hljs-comment">//后续拓展继续上传时可用</span><br>                _this.<span class="hljs-title function_">hanldeRemoveFile</span>(_this.<span class="hljs-property">uploadFiles</span>[index]);<br>                _this.<span class="hljs-title function_">onError</span>(_this.<span class="hljs-property">uploadFiles</span>[index]);<br>            &#125;<br>        &#125;<br>        xhr.<span class="hljs-property">onerror</span> = <span class="hljs-keyword">function</span>(<span class="hljs-params">e</span>) &#123;<br>            _this.<span class="hljs-property">errorChuncks</span>.<span class="hljs-title function_">push</span>(&#123;<span class="hljs-attr">file</span>:file,nowChunck,totalChunck,hash&#125;);<br>            <span class="hljs-title function_">reject</span>(<span class="hljs-literal">false</span>)<br>            _this.<span class="hljs-property">uploadQuantity</span> = <span class="hljs-number">0</span>;<br>            <span class="hljs-keyword">const</span> index = _this.<span class="hljs-property">uploadFiles</span>.<span class="hljs-title function_">findIndex</span>(<span class="hljs-function"><span class="hljs-params">item</span> =&gt;</span> item.<span class="hljs-property">hash</span> === hash);<br>            _this.$set(_this.<span class="hljs-property">uploadFiles</span>,index,&#123;..._this.<span class="hljs-property">uploadFiles</span>[index],...&#123;<span class="hljs-attr">status</span>: <span class="hljs-string">&#x27;error&#x27;</span>&#125;&#125;); <span class="hljs-comment">//后续拓展继续上传时可用</span><br>            _this.<span class="hljs-title function_">hanldeRemoveFile</span>(_this.<span class="hljs-property">uploadFiles</span>[index]);<br>            _this.<span class="hljs-title function_">onError</span>(_this.<span class="hljs-property">uploadFiles</span>[index]);<br>        &#125;<br>        <span class="hljs-comment">// 发送请求</span><br>        xhr.<span class="hljs-title function_">open</span>(<span class="hljs-string">&#x27;POST&#x27;</span>, _this.<span class="hljs-property">uploadApi</span>, <span class="hljs-literal">true</span>);<br>        <span class="hljs-keyword">if</span> (_this.<span class="hljs-property">apiHeader</span>?.<span class="hljs-property">withCredentials</span> &amp;&amp; <span class="hljs-string">&#x27;withCredentials&#x27;</span> <span class="hljs-keyword">in</span> xhr) &#123;<br>            xhr.<span class="hljs-property">withCredentials</span> = <span class="hljs-literal">true</span>;<br>        &#125;<br>        <span class="hljs-keyword">const</span> headers = _this.<span class="hljs-property">apiHeader</span> || &#123;&#125;;<br>        <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> item <span class="hljs-keyword">in</span> headers) &#123;<br>            <span class="hljs-keyword">if</span> (headers.<span class="hljs-title function_">hasOwnProperty</span>(item) &amp;&amp; headers[item] !== <span class="hljs-literal">null</span>) &#123;<br>                xhr.<span class="hljs-title function_">setRequestHeader</span>(item, headers[item]);<br>            &#125;<br>        &#125;<br>        xhr.<span class="hljs-title function_">send</span>(file);<br>    &#125;);<br>    _this.<span class="hljs-property">promiseArr</span>.<span class="hljs-title function_">push</span>(curPormise);<br>    <span class="hljs-keyword">return</span> curPormise;<br>&#125;<br></code></pre></td></tr></table></figure>

<h3 id="第四步：合并文件"><a href="#第四步：合并文件" class="headerlink" title="第四步：合并文件"></a>第四步：合并文件</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">async</span> mergeFile (fileInfo,chunckTotal)&#123;<br>    <span class="hljs-keyword">const</span> &#123; md5Value,fileKey &#125;  = fileInfo;<br>    <span class="hljs-keyword">const</span> params = &#123;<br>        <span class="hljs-attr">totalNumber</span>:chunckTotal,<br>        <span class="hljs-attr">md5</span>:md5Value,<br>        <span class="hljs-attr">name</span>:fileKey<br>    &#125;<br>    <span class="hljs-keyword">const</span> index = <span class="hljs-variable language_">this</span>.<span class="hljs-property">uploadFiles</span>.<span class="hljs-title function_">findIndex</span>(<span class="hljs-function"><span class="hljs-params">item</span> =&gt;</span> item.<span class="hljs-property">hash</span> === md5Value);<br>    <span class="hljs-keyword">try</span> &#123;<br>        <span class="hljs-keyword">const</span> &#123;code,data&#125; = <span class="hljs-keyword">await</span> <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">request</span>(&#123;<span class="hljs-attr">url</span>:<span class="hljs-string">`<span class="hljs-subst">$&#123;<span class="hljs-variable language_">this</span>.mergeApi&#125;</span>?uuid=<span class="hljs-subst">$&#123;md5Value&#125;</span>`</span>, <span class="hljs-attr">method</span>: <span class="hljs-string">&#x27;get&#x27;</span>&#125;);<br>        <span class="hljs-keyword">if</span>(code === <span class="hljs-number">200</span>) &#123;<br>            <span class="hljs-variable language_">this</span>.$set(<span class="hljs-variable language_">this</span>.<span class="hljs-property">uploadFiles</span>,index,&#123;...<span class="hljs-variable language_">this</span>.<span class="hljs-property">uploadFiles</span>[index],...&#123;<span class="hljs-attr">status</span>: <span class="hljs-string">&#x27;success&#x27;</span>,<span class="hljs-attr">url</span>:data&#125;&#125;); <span class="hljs-comment">//记得绑定url</span><br>            <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">onSuccess</span>(<span class="hljs-variable language_">this</span>.<span class="hljs-property">uploadFiles</span>[index],data);<br>        &#125;<br>    &#125;<span class="hljs-keyword">catch</span>(e) &#123;<br>        <span class="hljs-variable language_">this</span>.$set(<span class="hljs-variable language_">this</span>.<span class="hljs-property">uploadFiles</span>,index,&#123;...<span class="hljs-variable language_">this</span>.<span class="hljs-property">uploadFiles</span>[index],...&#123;<span class="hljs-attr">status</span>: <span class="hljs-string">&#x27;error&#x27;</span>,<span class="hljs-attr">url</span>:<span class="hljs-string">&#x27;&#x27;</span>&#125;&#125;); <span class="hljs-comment">//记得绑定url</span><br>        <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">hanldeRemoveFile</span>(<span class="hljs-variable language_">this</span>.<span class="hljs-property">uploadFiles</span>[index]);<br>        <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">onError</span>(<span class="hljs-variable language_">this</span>.<span class="hljs-property">uploadFiles</span>[index]);<br>    &#125;<br>    <span class="hljs-variable language_">this</span>.<span class="hljs-property">uploadQuantity</span> = <span class="hljs-number">0</span>;<br>    <span class="hljs-variable language_">this</span>.<span class="hljs-property">errorChuncks</span> = [];<br>&#125;,<br><br></code></pre></td></tr></table></figure>

<p>案例</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br></pre></td><td class="code"><pre><code class="hljs js">&lt;<span class="hljs-title class_">BigUpload</span> :<span class="hljs-title class_">SparkMD5</span>=<span class="hljs-string">&quot;SparkMD5&quot;</span> :request=<span class="hljs-string">&quot;request&quot;</span> <br>    :uploadApi=<span class="hljs-string">&quot;uploadApi&quot;</span> <br>    :mergeApi=<span class="hljs-string">&quot;mergeApi&quot;</span> <br>    :checkApi=<span class="hljs-string">&quot;checkApi&quot;</span><br>    :fileList=<span class="hljs-string">&quot;videoFileList&quot;</span><br>    :on-change=<span class="hljs-string">&quot;onChange&quot;</span><br>    :on-remove=<span class="hljs-string">&quot;handleRemove&quot;</span><br>    :on-progress=<span class="hljs-string">&quot;onProgress&quot;</span><br>    :before-upload=<span class="hljs-string">&quot;beforeUpload&quot;</span><br>    :on-exceed=<span class="hljs-string">&quot;onExceed&quot;</span><br>    :on-success=<span class="hljs-string">&quot;onSuccess&quot;</span><br>    :on-error=<span class="hljs-string">&quot;onError&quot;</span><br>    :on-preview=<span class="hljs-string">&quot;onPreview&quot;</span><br>    :on-reading-file=<span class="hljs-string">&quot;onReadingFile&quot;</span><br>    :limit=<span class="hljs-string">&quot;10&quot;</span><br>    :apiHeader=<span class="hljs-string">&quot;apiHeader&quot;</span><br>    :accept=<span class="hljs-string">&#x27;`mp4,avi,mov,wmv,3gp`&#x27;</span><br>&gt;<br>    <span class="language-xml"><span class="hljs-tag">&lt;<span class="hljs-name">el-button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">&quot;primary&quot;</span> <span class="hljs-attr">:disabled</span>=<span class="hljs-string">&quot;disabledUpload&quot;</span> <span class="hljs-attr">:loading</span>=<span class="hljs-string">&quot;loadingUpload&quot;</span>&gt;</span>&#123;&#123;loadingUpload ? $t(&#x27;workGuide.FileLoading&#x27;) : $t(&#x27;workGuide.ClickToUpload&#x27;) &#125;&#125;<span class="hljs-tag">&lt;/<span class="hljs-name">el-button</span>&gt;</span></span><br>     <span class="language-xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">slot</span>=<span class="hljs-string">&quot;tip&quot;</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;el-upload__tip&quot;</span>&gt;</span>只能上传mp4,avi,mov,wmv,3gp文件，且不超过2G<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span><br>&lt;/<span class="hljs-title class_">BigUpload</span>&gt;<br><br><span class="hljs-title function_">onChange</span>(<span class="hljs-params">file,fileList</span>) &#123;<br>    <span class="hljs-variable language_">this</span>.<span class="hljs-property">disabledUpload</span> = <span class="hljs-literal">true</span>;<br>&#125;,<br><br><span class="hljs-comment">//读取文件回调，大文件读取耗时较长，给一个loading状态过度</span><br><span class="hljs-title function_">onReadingFile</span>(<span class="hljs-params">value</span>)&#123;<br>    value === <span class="hljs-string">&#x27;start&#x27;</span> ?  <span class="hljs-variable language_">this</span>.<span class="hljs-property">loadingUpload</span> = <span class="hljs-literal">true</span> : <span class="hljs-variable language_">this</span>.<span class="hljs-property">loadingUpload</span> = <span class="hljs-literal">false</span>;<br>&#125;,<br><br><span class="hljs-title function_">beforeUpload</span>(<span class="hljs-params">file</span>) &#123;<br>    <span class="hljs-keyword">const</span> type = file.<span class="hljs-property">type</span>.<span class="hljs-title function_">split</span>(<span class="hljs-string">&#x27;/&#x27;</span>)[<span class="hljs-number">0</span>];<br>    <span class="hljs-keyword">const</span> isVideo = type === <span class="hljs-string">&#x27;video&#x27;</span>;<br>    <span class="hljs-keyword">const</span> isLt2G = file.<span class="hljs-property">size</span> / <span class="hljs-number">1024</span> / <span class="hljs-number">1024</span> &lt; <span class="hljs-number">2048</span>;<br>    <span class="hljs-keyword">if</span> (!isLt2G) &#123;<br>        <span class="hljs-variable language_">this</span>.<span class="hljs-property">$message</span>.<span class="hljs-title function_">error</span>(<span class="hljs-variable language_">this</span>.$t(<span class="hljs-string">&#x27;KOLProductBoard.MaximumSizeImages&#x27;</span>,&#123;<span class="hljs-attr">m</span>:<span class="hljs-string">&#x27;2048&#x27;</span>&#125;))<br>    &#125;<br>    <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (!isVideo) &#123;<br>        <span class="hljs-variable language_">this</span>.<span class="hljs-property">$message</span>.<span class="hljs-title function_">error</span>(<span class="hljs-variable language_">this</span>.$t(<span class="hljs-string">&#x27;workGuide.uploadFormatTip&#x27;</span>,&#123;<span class="hljs-attr">m</span>:<span class="hljs-string">&#x27;mp4,avi,mov,wmv,3gp&#x27;</span>&#125;))<br>    &#125;<br>    <span class="hljs-keyword">return</span> isVideo &amp;&amp; isLt2G;<br>&#125;,<br><br><span class="hljs-comment">//超过最大上传数量回调</span><br><span class="hljs-title function_">onExceed</span>(<span class="hljs-params">file,fileList</span>) &#123;<br>    <span class="hljs-variable language_">this</span>.<span class="hljs-property">$message</span>.<span class="hljs-title function_">warning</span>(<span class="hljs-variable language_">this</span>.$t(<span class="hljs-string">&#x27;KOLProductBoard.MaximumLimitImages&#x27;</span>, &#123; <span class="hljs-attr">m</span>: <span class="hljs-string">&#x27;10&#x27;</span>&#125;));<br>&#125;,<br><br><span class="hljs-comment">//上传进度回调</span><br><span class="hljs-title function_">onProgress</span>(<span class="hljs-params">file,percentage</span>) &#123;<br><br>&#125;,<br><br><span class="hljs-comment">//预览回调</span><br><span class="hljs-title function_">onPreview</span>(<span class="hljs-params">&#123;url&#125;</span>) &#123;<br>    <span class="hljs-variable language_">this</span>.<span class="hljs-property">bigImageUrl</span> = url;<br>    <span class="hljs-variable language_">this</span>.<span class="hljs-property">showBigImage</span> = <span class="hljs-literal">true</span>;<br>&#125;,<br><br><span class="hljs-title function_">onSuccess</span>(<span class="hljs-params">file,url</span>) &#123;<br>    <span class="hljs-variable language_">this</span>.<span class="hljs-property">videoFileList</span>.<span class="hljs-title function_">push</span>(file);<br>    <span class="hljs-variable language_">this</span>.<span class="hljs-property">disabledUpload</span> = <span class="hljs-literal">false</span>;<br>    <span class="hljs-variable language_">this</span>.<span class="hljs-property">$message</span>.<span class="hljs-title function_">success</span>(<span class="hljs-variable language_">this</span>.$t(<span class="hljs-string">&#x27;KOL需求管理.UploadSuccessful&#x27;</span>));<br>&#125;,<br><br><span class="hljs-title function_">onError</span>(<span class="hljs-params">file,reason</span>) &#123;<br>    <span class="hljs-comment">//reason 是在浏览器读取文件失败时特有的参数</span><br>    <span class="hljs-comment">//禁用上传</span><br>    <span class="hljs-variable language_">this</span>.<span class="hljs-property">disabledUpload</span> = <span class="hljs-literal">false</span>;<br>    <span class="hljs-keyword">if</span>(reason) &#123;<br>        <span class="hljs-variable language_">this</span>.<span class="hljs-property">loadingUpload</span> = <span class="hljs-literal">false</span>;<br>        <span class="hljs-variable language_">this</span>.<span class="hljs-property">$message</span>.<span class="hljs-title function_">error</span>(reason);<br>    &#125;<span class="hljs-keyword">else</span> &#123;<br>        <span class="hljs-variable language_">this</span>.<span class="hljs-property">$message</span>.<span class="hljs-title function_">success</span>(<span class="hljs-variable language_">this</span>.$t(<span class="hljs-string">&#x27;workGuide.UploadFailed&#x27;</span>));<br>    &#125;<br>&#125;,<br><br><span class="hljs-title function_">handleRemove</span>(<span class="hljs-params">file,fileList</span>) &#123;<br>    <span class="hljs-variable language_">this</span>.<span class="hljs-property">videoFileList</span> = [...fileList];<br>&#125;,<br><br></code></pre></td></tr></table></figure>

<h2 id="后端代码"><a href="#后端代码" class="headerlink" title="后端代码"></a>后端代码</h2><h3 id="x2F-upload-接口"><a href="#x2F-upload-接口" class="headerlink" title="&#x2F;upload 接口"></a>&#x2F;upload 接口</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">const</span> <span class="hljs-title function_">insertFile</span> = <span class="hljs-keyword">async</span> (<span class="hljs-params">md5,name,totalNumber,chunkSize,chunckNumber</span>) =&gt; &#123;<br>    <span class="hljs-keyword">const</span> sql = <span class="hljs-string">`INSERT INTO fileupload.chunck_list (file_hash,chunck_number,chunck_size,chunck_total_number,file_name) VALUES (&#x27;<span class="hljs-subst">$&#123;md5&#125;</span>&#x27;,&#x27;<span class="hljs-subst">$&#123;chunckNumber&#125;</span>&#x27;,&#x27;<span class="hljs-subst">$&#123;chunkSize&#125;</span>&#x27;,&#x27;<span class="hljs-subst">$&#123;totalNumber&#125;</span>&#x27;,&#x27;<span class="hljs-subst">$&#123;name&#125;</span>&#x27;)`</span>;<br>    <span class="hljs-keyword">const</span> result = <span class="hljs-keyword">await</span> connection.<span class="hljs-title function_">query</span>(sql);<br>    <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(result + <span class="hljs-string">&#x27;数据插入成功&#x27;</span>)<br>&#125;<br><br>router.<span class="hljs-title function_">post</span>(<span class="hljs-string">&quot;/upload&quot;</span>,upload.<span class="hljs-title function_">single</span>(<span class="hljs-string">&quot;file&quot;</span>), <span class="hljs-keyword">async</span> (ctx, next) =&gt; &#123;<br>    <span class="hljs-keyword">const</span> &#123;<br>        totalNumber,  <span class="hljs-comment">// 分片总数</span><br>        chunckNumber, <span class="hljs-comment">// 分片序号</span><br>        chunkSize,    <span class="hljs-comment">// 分片大小</span><br>        md5,          <span class="hljs-comment">// 文件hash值（唯一）</span><br>        name          <span class="hljs-comment">// 文件名称</span><br>    &#125; = ctx.<span class="hljs-property">req</span>.<span class="hljs-property">body</span>;<br>    <span class="hljs-comment">//指定hash文件路径</span><br>    <span class="hljs-keyword">const</span> chunckPath = path.<span class="hljs-title function_">join</span>(uploadPath, md5,<span class="hljs-string">&#x27;/&#x27;</span>);<br>    <span class="hljs-keyword">if</span>(!fs.<span class="hljs-title function_">existsSync</span>(chunckPath))&#123;<br>        fs.<span class="hljs-title function_">mkdirSync</span>(chunckPath);<br>    &#125;<br>    <span class="hljs-comment">//移动文件到指定目录</span><br>    fs.<span class="hljs-title function_">renameSync</span>(ctx.<span class="hljs-property">req</span>.<span class="hljs-property">file</span>.<span class="hljs-property">path</span>,chunckPath + md5 + <span class="hljs-string">&#x27;-&#x27;</span> + chunckNumber);<br>    <span class="hljs-title function_">insertFile</span>(md5,name,totalNumber,chunkSize,chunckNumber)<br>    ctx.<span class="hljs-property">status</span> = <span class="hljs-number">200</span>;<br>    ctx.<span class="hljs-property">res</span>.<span class="hljs-title function_">end</span>(<span class="hljs-string">&#x27;Success&#x27;</span>);<br>&#125;)<br><br></code></pre></td></tr></table></figure>

<h3 id="x2F-merge接口"><a href="#x2F-merge接口" class="headerlink" title="&#x2F;merge接口"></a>&#x2F;merge接口</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><code class="hljs js">router.<span class="hljs-title function_">post</span>(<span class="hljs-string">&quot;/merge&quot;</span>, <span class="hljs-keyword">async</span> (ctx, next) =&gt; &#123;<br>    <span class="hljs-keyword">const</span> &#123;totalNumber,md5,name&#125; = ctx.<span class="hljs-property">request</span>.<span class="hljs-property">body</span>;<br>    <span class="hljs-keyword">try</span> &#123;<br>        <span class="hljs-comment">//分片存储得文件夹路径</span><br>        <span class="hljs-keyword">const</span> chunckPath = path.<span class="hljs-title function_">join</span>(uploadPath, md5, <span class="hljs-string">&#x27;/&#x27;</span>);<br>        <span class="hljs-comment">//创建合并后的文件</span><br>        <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(name+<span class="hljs-string">&#x27;我是视频地址&#x27;</span>)<br>        <span class="hljs-keyword">const</span> filePath = path.<span class="hljs-title function_">join</span>(uploadPath, name);<br>        <span class="hljs-comment">//读取对应hash文件夹下的所有分片文件名称</span><br>        <span class="hljs-keyword">const</span> chunckList = fs.<span class="hljs-title function_">existsSync</span>(chunckPath) ? fs.<span class="hljs-title function_">readdirSync</span>(chunckPath) : [];<br>        <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(chunckList+<span class="hljs-string">&#x27;我是视频地址&#x27;</span>)<br>        <span class="hljs-comment">//创建储存文件</span><br>        fs.<span class="hljs-title function_">writeFileSync</span>(filePath,<span class="hljs-string">&#x27;&#x27;</span>);<br>        <span class="hljs-comment">//判断切片是否完整</span><br>        <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(chunckList.<span class="hljs-property">length</span>,totalNumber,<span class="hljs-string">&#x27;我是总地址，和分片地址&#x27;</span>)<br>        <span class="hljs-keyword">if</span>(chunckList.<span class="hljs-property">length</span> !== totalNumber)&#123;<br>            ctx.<span class="hljs-property">status</span> = <span class="hljs-number">500</span>;<br>            ctx.<span class="hljs-property">message</span> = <span class="hljs-string">&#x27;Merge failed, missing file slices&#x27;</span>;<br>            <span class="hljs-comment">// ctx.res.end(&#x27;error&#x27;);</span><br>            process.<span class="hljs-title function_">exit</span>();<br>        &#125;<br>        <span class="hljs-keyword">for</span>(<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; totalNumber; i++)&#123;<br>            <span class="hljs-keyword">const</span> chunck = fs.<span class="hljs-title function_">readFileSync</span>(chunckPath +md5+ <span class="hljs-string">&#x27;-&#x27;</span> + i);<br>            <span class="hljs-comment">//写入当前切片</span><br>            fs.<span class="hljs-title function_">appendFileSync</span>(filePath,chunck);<br>            <span class="hljs-comment">//删除已合并的切片 </span><br>            fs.<span class="hljs-title function_">unlinkSync</span>(chunckPath + md5 + <span class="hljs-string">&#x27;-&#x27;</span> + i);<br>        &#125;<br>        <span class="hljs-comment">//删除空文件夹</span><br>        fs.<span class="hljs-title function_">rmdirSync</span>(chunckPath); <br>        ctx.<span class="hljs-property">status</span> = <span class="hljs-number">200</span>;<br>        ctx.<span class="hljs-property">message</span> = <span class="hljs-string">&#x27;success&#x27;</span>;<br>    &#125;<span class="hljs-keyword">catch</span> (e) &#123;<br>        ctx.<span class="hljs-property">status</span> = <span class="hljs-number">500</span>;<br>        ctx.<span class="hljs-property">res</span>.<span class="hljs-title function_">end</span>(<span class="hljs-string">&#x27;合并失败&#x27;</span>);<br>    &#125;<br>&#125;)<br></code></pre></td></tr></table></figure>

<h3 id="x2F-checkChuncks-接口"><a href="#x2F-checkChuncks-接口" class="headerlink" title="&#x2F;checkChuncks 接口"></a>&#x2F;checkChuncks 接口</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><code class="hljs js">router.<span class="hljs-title function_">post</span>(<span class="hljs-string">&quot;/checkChuncks&quot;</span>, <span class="hljs-keyword">async</span> (ctx, next) =&gt; &#123;<br>    <span class="hljs-keyword">try</span> &#123;<br>        <span class="hljs-keyword">const</span> &#123;md5&#125; = ctx.<span class="hljs-property">request</span>.<span class="hljs-property">body</span>;<br>        <span class="hljs-keyword">const</span> queryResult = <span class="hljs-keyword">await</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">Promise</span>(<span class="hljs-function">(<span class="hljs-params">resolve,reject</span>)=&gt;</span>&#123;<br>            <span class="hljs-keyword">const</span> query = <span class="hljs-string">`SELECT  (SELECT count(*)  FROM chunck_list WHERE file_hash = &#x27;<span class="hljs-subst">$&#123;md5&#125;</span>&#x27;) as all_count, id as chunck_id,file_hash,chunck_number,chunck_total_number FROM chunck_list  WHERE file_hash = &#x27;<span class="hljs-subst">$&#123;md5&#125;</span>&#x27; GROUP BY id ORDER BY chunck_number`</span>;<br>            connection.<span class="hljs-title function_">query</span>(query,<span class="hljs-keyword">async</span> (error,results,fields)=&gt;&#123;<br>                <span class="hljs-keyword">if</span>(error) <span class="hljs-title function_">reject</span>(error);<br>                <span class="hljs-title function_">resolve</span>(results || []);<br>            &#125;);  <br>        &#125;)<br>        ctx.<span class="hljs-property">status</span> = <span class="hljs-number">200</span>;<br>        ctx.<span class="hljs-property">body</span> = queryResult;<br>    &#125;<span class="hljs-keyword">catch</span> (e) &#123;<br>        ctx.<span class="hljs-property">status</span> = <span class="hljs-number">500</span>;<br>        ctx.<span class="hljs-property">res</span>.<span class="hljs-title function_">end</span>(<span class="hljs-string">&#x27;error&#x27;</span>);<br>    &#125;<br>&#125;)<br></code></pre></td></tr></table></figure>

<h3 id="数据库表结构"><a href="#数据库表结构" class="headerlink" title="数据库表结构"></a>数据库表结构</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-variable constant_">CREATE</span> <span class="hljs-variable constant_">TABLE</span> <span class="hljs-string">`chunck_list`</span> (<br>  <span class="hljs-string">`id`</span> int <span class="hljs-variable constant_">NOT</span> <span class="hljs-variable constant_">NULL</span> <span class="hljs-variable constant_">AUTO_INCREMENT</span>,<br>  <span class="hljs-string">`file_hash`</span> <span class="hljs-title function_">varchar</span>(<span class="hljs-number">255</span>) <span class="hljs-variable constant_">DEFAULT</span> <span class="hljs-variable constant_">NULL</span> <span class="hljs-variable constant_">COMMENT</span> <span class="hljs-string">&#x27;文件的唯一以hash值&#x27;</span>,<br>  <span class="hljs-string">`chunck_number`</span> int <span class="hljs-variable constant_">DEFAULT</span> <span class="hljs-variable constant_">NULL</span> <span class="hljs-variable constant_">COMMENT</span> <span class="hljs-string">&#x27;分片序号&#x27;</span>,<br>  <span class="hljs-string">`chunck_size`</span> <span class="hljs-title function_">varchar</span>(<span class="hljs-number">255</span>) <span class="hljs-variable constant_">DEFAULT</span> <span class="hljs-variable constant_">NULL</span> <span class="hljs-variable constant_">COMMENT</span> <span class="hljs-string">&#x27;分片大小&#x27;</span>,<br>  <span class="hljs-string">`file_name`</span> <span class="hljs-title function_">varchar</span>(<span class="hljs-number">255</span>) <span class="hljs-variable constant_">DEFAULT</span> <span class="hljs-variable constant_">NULL</span> <span class="hljs-variable constant_">COMMENT</span> <span class="hljs-string">&#x27;文件名称&#x27;</span>,<br>  <span class="hljs-string">`chunck_total_number`</span> <span class="hljs-title function_">varchar</span>(<span class="hljs-number">255</span>) <span class="hljs-variable constant_">DEFAULT</span> <span class="hljs-variable constant_">NULL</span> <span class="hljs-variable constant_">COMMENT</span> <span class="hljs-string">&#x27;总分片数&#x27;</span>,<br>  <span class="hljs-variable constant_">PRIMARY</span> <span class="hljs-variable constant_">KEY</span> (<span class="hljs-string">`id`</span>)<br>) <span class="hljs-variable constant_">ENGINE</span>=<span class="hljs-title class_">InnoDB</span> <span class="hljs-variable constant_">AUTO_INCREMENT</span>=<span class="hljs-number">55902</span> <span class="hljs-variable constant_">DEFAULT</span> <span class="hljs-variable constant_">CHARSET</span>=utf8mb4 <span class="hljs-variable constant_">COLLATE</span>=utf8mb4_0900_ai_ci;<br></code></pre></td></tr></table></figure>

<h3 id="所需依赖"><a href="#所需依赖" class="headerlink" title="所需依赖"></a>所需依赖</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-string">&quot;dependencies&quot;</span>: &#123;<br>   <span class="hljs-string">&quot;fs-extra&quot;</span>: <span class="hljs-string">&quot;^11.2.0&quot;</span>,<br>   <span class="hljs-string">&quot;koa&quot;</span>: <span class="hljs-string">&quot;^2.14.2&quot;</span>,<br>   <span class="hljs-string">&quot;koa-body&quot;</span>: <span class="hljs-string">&quot;^6.0.1&quot;</span>,<br>   <span class="hljs-string">&quot;koa-multer&quot;</span>: <span class="hljs-string">&quot;^1.0.2&quot;</span>,<br>   <span class="hljs-string">&quot;koa-router&quot;</span>: <span class="hljs-string">&quot;^12.0.0&quot;</span>,<br>   <span class="hljs-string">&quot;koa-static&quot;</span>: <span class="hljs-string">&quot;^5.0.0&quot;</span>,<br>   <span class="hljs-string">&quot;koa2-cors&quot;</span>: <span class="hljs-string">&quot;^2.0.6&quot;</span>,<br>   <span class="hljs-string">&quot;mysql&quot;</span>: <span class="hljs-string">&quot;^2.18.1&quot;</span>,<br>   <span class="hljs-string">&quot;nodemon&quot;</span>: <span class="hljs-string">&quot;^2.0.22&quot;</span><br> &#125;<br></code></pre></td></tr></table></figure>










                
              </div>
            
            <hr/>
            <div>
              <div class="post-metas my-3">
  
    <div class="post-meta mr-3 d-flex align-items-center">
      <i class="iconfont icon-category"></i>
      

<span class="category-chains">
  
  
    
      <span class="category-chain">
        
  <a href="/blog/categories/%E5%89%8D%E7%AB%AF%E6%8A%80%E6%9C%AF%E6%A0%88/" class="category-chain-item">前端技术栈</a>
  
  
    <span>></span>
    
  <a href="/blog/categories/%E5%89%8D%E7%AB%AF%E6%8A%80%E6%9C%AF%E6%A0%88/%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96/" class="category-chain-item">性能优化</a>
  
  

  

      </span>
    
  
</span>

    </div>
  
  
    <div class="post-meta">
      <i class="iconfont icon-tags"></i>
      
        <a href="/blog/tags/%E5%88%86%E7%89%87/">#分片</a>
      
    </div>
  
</div>


              
  

  <div class="license-box my-3">
    <div class="license-title">
      <div>断点续存</div>
      <div>https://airfe.gitee.io/blog/2024/03/21/断点续存/</div>
    </div>
    <div class="license-meta">
      
        <div class="license-meta-item">
          <div>作者</div>
          <div>Airfe</div>
        </div>
      
      
        <div class="license-meta-item license-meta-date">
          <div>发布于</div>
          <div>2024年3月21日</div>
        </div>
      
      
      
        <div class="license-meta-item">
          <div>许可协议</div>
          <div>
            
              
              
                <a target="_blank" href="https://creativecommons.org/licenses/by/4.0/">
                  <span class="hint--top hint--rounded" aria-label="BY - 署名">
                    <i class="iconfont icon-by"></i>
                  </span>
                </a>
              
            
          </div>
        </div>
      
    </div>
    <div class="license-icon iconfont"></div>
  </div>



              
                <div class="post-prevnext my-3">
                  <article class="post-prev col-6">
                    
                    
                      <a href="/blog/2024/04/09/TypeScript(%E4%B8%80)%20%E7%AE%80%E4%BB%8B%E5%92%8C%E5%9F%BA%E6%9C%AC%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B/" title="TypeScript(一) 简介和基本数据类型">
                        <i class="iconfont icon-arrowleft"></i>
                        <span class="hidden-mobile">TypeScript(一) 简介和基本数据类型</span>
                        <span class="visible-mobile">上一篇</span>
                      </a>
                    
                  </article>
                  <article class="post-next col-6">
                    
                    
                      <a href="/blog/2023/11/19/%E5%AE%A2%E6%88%B7%E7%AB%AF%E5%AD%98%E5%82%A8/" title="客户端存储">
                        <span class="hidden-mobile">客户端存储</span>
                        <span class="visible-mobile">下一篇</span>
                        <i class="iconfont icon-arrowright"></i>
                      </a>
                    
                  </article>
                </div>
              
            </div>

            
  
  
    <article id="comments" lazyload>
      
  <div id="valine"></div>
  <script type="text/javascript">
    Fluid.utils.loadComments('#valine', function() {
      Fluid.utils.createScript('https://lib.baomitu.com/valine/1.5.1/Valine.min.js', function() {
        var options = Object.assign(
          {"appId":"RW68dMkEpeIOJJiBr1lPkhOS-gzGzoHsz","appKey":"P5fzMTGSJIoTaGvmgzsUHeNZ","path":"window.location.pathname","placeholder":"发表你的看法吧~","avatar":"retro","meta":["nick","mail","link"],"requiredFields":[],"pageSize":10,"lang":"zh-CN","highlight":false,"recordIP":false,"serverURLs":"","emojiCDN":null,"emojiMaps":null,"enableQQ":false,"appid":"RW68dMkEpeIOJJiBr1lPkhOS-gzGzoHsz","appkey":"P5fzMTGSJIoTaGvmgzsUHeNZ","server_url":"https://rw68dmke.lc-cn-n1-shared.com"},
          {
            el: "#valine",
            path: window.location.pathname
          }
        )
        new Valine(options);
        Fluid.utils.waitElementVisible('#valine .vcontent', () => {
          var imgSelector = '#valine .vcontent img:not(.vemoji)';
          Fluid.plugins.imageCaption(imgSelector);
          Fluid.plugins.fancyBox(imgSelector);
        })
      });
    });
  </script>
  <noscript>Please enable JavaScript to view the comments</noscript>


    </article>
  


          </article>
        </div>
      </div>
    </div>

    <div class="side-col d-none d-lg-block col-lg-2">
      
  <aside class="sidebar" style="margin-left: -1rem">
    <div id="toc">
  <p class="toc-header">
    <i class="iconfont icon-list"></i>
    <span>目录</span>
  </p>
  <div class="toc-body" id="toc-body"></div>
</div>



  </aside>


    </div>
  </div>
</div>





  



  



  



  



  







    

    
      <a id="scroll-top-button" aria-label="TOP" href="#" role="button">
        <i class="iconfont icon-arrowup" aria-hidden="true"></i>
      </a>
    

    
      <div class="modal fade" id="modalSearch" tabindex="-1" role="dialog" aria-labelledby="ModalLabel"
     aria-hidden="true">
  <div class="modal-dialog modal-dialog-scrollable modal-lg" role="document">
    <div class="modal-content">
      <div class="modal-header text-center">
        <h4 class="modal-title w-100 font-weight-bold">搜索</h4>
        <button type="button" id="local-search-close" class="close" data-dismiss="modal" aria-label="Close">
          <span aria-hidden="true">&times;</span>
        </button>
      </div>
      <div class="modal-body mx-3">
        <div class="md-form mb-5">
          <input type="text" id="local-search-input" class="form-control validate">
          <label data-error="x" data-success="v" for="local-search-input">关键词</label>
        </div>
        <div class="list-group" id="local-search-result"></div>
      </div>
    </div>
  </div>
</div>

    

    
  </main>

  <footer>
    <div class="footer-inner">
  
    <div class="footer-content">
        <a href="https://hexo.io" target="_blank" rel="nofollow noopener"><span>Hexo</span></a> <i class="iconfont icon-love"></i> <a href="https://github.com/fluid-dev/hexo-theme-fluid" target="_blank" rel="nofollow noopener"><span>Fluid</span></a> <div style="font-size: 0.85rem"> <span id="timeDate">载入天数</span> <span id="times">载入时分秒</span> <script src="js/duration.js"></script> </div> 
    </div>
  
  
    <div class="statistics">
  
  

  
    
      <span id="leancloud-site-pv-container" style="display: none">
        总访问量 
        <span id="leancloud-site-pv"></span>
         次
      </span>
    
    
      <span id="leancloud-site-uv-container" style="display: none">
        总访客数 
        <span id="leancloud-site-uv"></span>
         人
      </span>
    
    

  
</div>

  
  
    <!-- 备案信息 ICP for China -->
    <div class="beian">
  <span>
    <a href="http://beian.miit.gov.cn/" target="_blank" rel="nofollow noopener">
      蜀ICP备2023008943号
    </a>
  </span>
  
    
      <span>
        <a
          href="http://www.beian.gov.cn/portal/registerSystemInfo?recordcode=https://beian.miit.gov.cn/"
          rel="nofollow noopener"
          class="beian-police"
          target="_blank"
        >
          
            <span style="visibility: hidden; width: 0">|</span>
            <img src="" srcset="/blog/img/loading.gif" lazyload data-original="/blog/img/police_beian.png" alt="police-icon"/>
          
          <span>京公网安备12345678号</span>
        </a>
      </span>
    
  
</div>

  
  
</div>

  </footer>

  <!-- Scripts -->
  
  <script  src="https://lib.baomitu.com/nprogress/0.2.0/nprogress.min.js" ></script>
  <link  rel="stylesheet" href="https://lib.baomitu.com/nprogress/0.2.0/nprogress.min.css" />

  <script>
    NProgress.configure({"showSpinner":false,"trickleSpeed":100})
    NProgress.start()
    window.addEventListener('load', function() {
      NProgress.done();
    })
  </script>


<script  src="https://lib.baomitu.com/jquery/3.6.0/jquery.min.js" ></script>
<script  src="https://lib.baomitu.com/twitter-bootstrap/4.6.1/js/bootstrap.min.js" ></script>
<script  src="/blog/js/events.js" ></script>
<script  src="/blog/js/plugins.js" ></script>


  <script  src="https://lib.baomitu.com/typed.js/2.0.12/typed.min.js" ></script>
  <script>
    (function (window, document) {
      var typing = Fluid.plugins.typing;
      var subtitle = document.getElementById('subtitle');
      if (!subtitle || !typing) {
        return;
      }
      var text = subtitle.getAttribute('data-typed-text');
      
        typing(text);
      
    })(window, document);
  </script>




  
    <script  src="/blog/js/img-lazyload.js" ></script>
  




  
<script>
  Fluid.utils.createScript('https://lib.baomitu.com/tocbot/4.18.2/tocbot.min.js', function() {
    var toc = jQuery('#toc');
    if (toc.length === 0 || !window.tocbot) { return; }
    var boardCtn = jQuery('#board-ctn');
    var boardTop = boardCtn.offset().top;

    window.tocbot.init(Object.assign({
      tocSelector     : '#toc-body',
      contentSelector : '.markdown-body',
      linkClass       : 'tocbot-link',
      activeLinkClass : 'tocbot-active-link',
      listClass       : 'tocbot-list',
      isCollapsedClass: 'tocbot-is-collapsed',
      collapsibleClass: 'tocbot-is-collapsible',
      scrollSmooth    : true,
      includeTitleTags: true,
      headingsOffset  : -boardTop,
    }, CONFIG.toc));
    if (toc.find('.toc-list-item').length > 0) {
      toc.css('visibility', 'visible');
    }

    Fluid.events.registerRefreshCallback(function() {
      if ('tocbot' in window) {
        tocbot.refresh();
        var toc = jQuery('#toc');
        if (toc.length === 0 || !tocbot) {
          return;
        }
        if (toc.find('.toc-list-item').length > 0) {
          toc.css('visibility', 'visible');
        }
      }
    });
  });
</script>


  <script src=https://lib.baomitu.com/clipboard.js/2.0.11/clipboard.min.js></script>

  <script>Fluid.plugins.codeWidget();</script>


  
<script>
  Fluid.utils.createScript('https://lib.baomitu.com/anchor-js/4.3.1/anchor.min.js', function() {
    window.anchors.options = {
      placement: CONFIG.anchorjs.placement,
      visible  : CONFIG.anchorjs.visible
    };
    if (CONFIG.anchorjs.icon) {
      window.anchors.options.icon = CONFIG.anchorjs.icon;
    }
    var el = (CONFIG.anchorjs.element || 'h1,h2,h3,h4,h5,h6').split(',');
    var res = [];
    for (var item of el) {
      res.push('.markdown-body > ' + item.trim());
    }
    if (CONFIG.anchorjs.placement === 'left') {
      window.anchors.options.class = 'anchorjs-link-left';
    }
    window.anchors.add(res.join(', '));

    Fluid.events.registerRefreshCallback(function() {
      if ('anchors' in window) {
        anchors.removeAll();
        var el = (CONFIG.anchorjs.element || 'h1,h2,h3,h4,h5,h6').split(',');
        var res = [];
        for (var item of el) {
          res.push('.markdown-body > ' + item.trim());
        }
        if (CONFIG.anchorjs.placement === 'left') {
          anchors.options.class = 'anchorjs-link-left';
        }
        anchors.add(res.join(', '));
      }
    });
  });
</script>


  
<script>
  Fluid.utils.createScript('https://lib.baomitu.com/fancybox/3.5.7/jquery.fancybox.min.js', function() {
    Fluid.plugins.fancyBox();
  });
</script>


  <script>Fluid.plugins.imageCaption();</script>

  <script defer src="/blog/js/leancloud.js" ></script>

  <script  src="/blog/js/local-search.js" ></script>





<!-- 主题的启动项，将它保持在最底部 -->
<!-- the boot of the theme, keep it at the bottom -->
<script  src="/blog/js/boot.js" ></script>


  

  <noscript>
    <div class="noscript-warning">博客在允许 JavaScript 运行的环境下浏览效果更佳</div>
  </noscript>

        <style>
            [bg-lazy] {
                background-image: none !important;
                background-color: #eee !important;
            }
        </style>
        <script>
            window.imageLazyLoadSetting = {
                isSPA: false,
                preloadRatio: 1,
                processImages: null,
            };
        </script><script>window.addEventListener("load",function(){var t=/\.(gif|jpg|jpeg|tiff|png)$/i,r=/^data:image\/[a-z]+;base64,/;Array.prototype.slice.call(document.querySelectorAll("img[data-original]")).forEach(function(a){var e=a.parentNode;"A"===e.tagName&&(e.href.match(t)||e.href.match(r))&&(e.href=a.dataset.original)})});</script><script>!function(r){r.imageLazyLoadSetting.processImages=t;var e=r.imageLazyLoadSetting.isSPA,n=r.imageLazyLoadSetting.preloadRatio||1,c=a();function a(){var t=Array.prototype.slice.call(document.querySelectorAll("img[data-original]")),e=Array.prototype.slice.call(document.querySelectorAll("[bg-lazy]"));return t.concat(e)}function t(){e&&(c=a());for(var t,o=0;o<c.length;o++)0<=(t=(t=c[o]).getBoundingClientRect()).bottom&&0<=t.left&&t.top<=(r.innerHeight*n||document.documentElement.clientHeight*n)&&function(){var t,e,n,a,i=c[o];e=function(){c=c.filter(function(t){return i!==t}),r.imageLazyLoadSetting.onImageLoaded&&r.imageLazyLoadSetting.onImageLoaded(i)},(t=i).hasAttribute("bg-lazy")?(t.removeAttribute("bg-lazy"),e&&e()):(n=new Image,a=t.getAttribute("data-original"),n.onload=function(){t.src=a,t.removeAttribute("data-original"),e&&e()},t.src!==a&&(n.src=a))}()}function i(){clearTimeout(t.tId),t.tId=setTimeout(t,500)}t(),document.addEventListener("scroll",i),r.addEventListener("resize",i),r.addEventListener("orientationchange",i)}(this);</script></body>
</html>
